#include "workCmd.h"

int workCmd(int netFd)
{
    client_t *client = (client_t*)calloc(1,sizeof(client_t));
    client->fd = netFd;

    //获取客户端名字
    int nameLength = 0;
    recvn(netFd,&nameLength,sizeof(int));
    recvn(netFd,client->userName,nameLength);

    char sysinfo[1024] = {0};
    strcpy(sysinfo,"connected");
    sysadd(client,sysinfo);

    //pwd保存基地址
    char pwd[1024];
    getcwd(pwd,sizeof(pwd));
    strcpy(client->baseDir,pwd);
    strcpy(client->pwd,"/");
    //获取当前路径（基地址）
    printf("%s is connet ,pwd is %s fd = %d.\n",
           client->userName,pwd,client->fd);

    while(1){
        printf("%s$ \n",pwd);
        //接受命令
        TLVtrain_t tlv;
        bzero(&tlv,sizeof(tlv));
        recvn(netFd,&tlv.type,sizeof(tlv.type));
        recvn(netFd,&tlv.length,sizeof(tlv.length));
        recvn(netFd,tlv.data,tlv.length);
        printf("type = %d data = %s,cmdLength = %d\n",tlv.type,tlv.data,tlv.length);

        bzero(sysinfo,sizeof(sysinfo));
        //分析命令
        if(tlv.type == CD){
            strcpy(sysinfo,"cd");
            doCd(client,tlv.data);
        }
        else if(tlv.type == LS){
            strcpy(sysinfo,"ls");
            doLs(client);
        }
        else if(tlv.type == LL){
            strcpy(sysinfo,"ll");
            doLl(client);
        }
        else if(tlv.type == PUTS){
            strcpy(sysinfo,"puts");
            doPuts(client);
        }
        else if(tlv.type == GETS){
            strcpy(sysinfo,"gets");
            doGets(client,tlv.data);
        }
        else if(tlv.type == REMOVE){
            strcpy(sysinfo,"remove");
            doRemove(client,tlv.data);
        }
        else if(tlv.type == MKDIR){
            strcpy(sysinfo,"mkdir");
            doMkdir(client,tlv.data);
        }
        else if(tlv.type == RMDIR){
            strcpy(sysinfo,"rmkdir");
            doRmdir(client,tlv.data);
        }
        else if(tlv.type == QUIT || tlv.length == 0){
            strcpy(sysinfo,"quit");
            sysadd(client,sysinfo);
            printf("%s has finished.\n",client->userName);
            free(client);
            break;
        }
        sysadd(client,sysinfo);
    }
    return 0;
}

int doCd(client_t *pclient,char * path){
    // 分割客户端传入的路径，token[]存每一层目录
    printf("Begin path :%s\n",path);
    char *tokens[64];
    int token_count = 0;
    char *saveptr = NULL;

    char path_copy[1024];
    strncpy(path_copy,path,sizeof(path_copy)-1);
    path_copy[sizeof(path_copy)-1] = '\0';

    char *token = strtok_r(path_copy, "/", &saveptr);
    while (token != NULL && token_count < 64) {
        tokens[token_count++] = token;
        token = strtok_r(NULL, "/", &saveptr);
    }

    PathStack *stack = pathstack_init();
    if(!stack) return -1;

    for (int i = 0; i < token_count; ++i) {
        // 如果是路径第一个部分，且与 user_dir 相同，跳过不入栈
        if (strcmp(tokens[i],".") == 0) continue;
        else if (strcmp(tokens[i], "..") == 0) {
            if(stack->size > 0){
                pathstack_pop(stack);    
            }
        }else {
            pathstack_push(tokens[i],stack);
        }
    }
    char relativePath[1024] = {0};
    if (stack->size == 0) {
        relativePath[0] = '\0';
        /* strcpy(relativePath,"/"); */
        // 绝对路径：从用户传入的路径重新构建栈
    } else {
        // 相对路径：先用 pclient->pwd 拆分构建初始路径栈
        PathNode *curr = stack->bottom;
        strcat(relativePath, curr->filePath);
        curr = curr->next;
        while (curr != NULL) {
            strcat(relativePath, "/");
            strcat(relativePath, curr->filePath);
            curr = curr->next;
        }
    }
    // 构建完整真实路径（基地址 + 相对路径）
    char realPath[2048];
    snprintf(realPath,sizeof(realPath),"%s/%s",pclient->baseDir,relativePath);
    printf("完整路径: %s\n", realPath);
    // 校验路径是否存在
    train_t train;
    int ret = access(realPath, F_OK);
    if (ret == -1) {
        printf("Path error\n");
        pathstack_free(stack);
        char msg[4096] = "Path error";
        train.length = strlen(msg);
        memcpy(train.data, msg, train.length);
        send(pclient->fd, &train.length, sizeof(train.length), MSG_NOSIGNAL);
        send(pclient->fd, train.data, train.length, MSG_NOSIGNAL);
        return -1;
    }else{
        // 更新客户端当前路径
        char temp[4096] = {0};
        if (strlen(relativePath) == 0) {
            strcpy(pclient->pwd,"/");
        } else {
            snprintf(temp, sizeof(temp), "/%s", relativePath);
            strcat(pclient->pwd,temp);
        }
        /* strncpy(pclient->pwd, relativePath,sizeof(pclient->pwd)-1); */
        /* pclient->pwd[sizeof(pclient->pwd)-1] = '\0'; */
        train.length = strlen(pclient->pwd);
        memcpy(train.data, pclient->pwd, train.length);
        send(pclient->fd, &train.length, sizeof(train.length), MSG_NOSIGNAL);
        send(pclient->fd, train.data, train.length, MSG_NOSIGNAL);
        printf("FinalPath : %s\n",pclient->pwd);
    }
    pathstack_free(stack);
    return 0;
}

int doLs(client_t *pclient){
    char fullPath[2048];
    if (strcmp(pclient->pwd, "/") == 0) {
        snprintf(fullPath, sizeof(fullPath), "%s", pclient->baseDir);  // 基地址
    } else {
        snprintf(fullPath, sizeof(fullPath), "%s%s", pclient->baseDir, pclient->pwd); // 拼接绝对路径
    }

    DIR *dir = opendir(fullPath);  // 使用完整绝对路径
    ERROR_CHECK(dir, NULL, "opendir");

    train_t train;
    struct dirent *dirent_p;
    while((dirent_p = readdir(dir))!= NULL){
        bzero(&train,sizeof(train));
        train.length = strlen(dirent_p->d_name);
        strcpy(train.data,dirent_p->d_name);
        /* printf("%s ",train.data); */
        send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);
    }
    bzero(&train,sizeof(train));
    send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);
    closedir(dir);
    return 0;
}

static void trans_rwx(mode_t mode,char *mode_str);
static void trans_time(time_t mtime,char *time_str);
static int compare(const void *a,const void *b);

int doLl(client_t *pclient){
    DIR *dir = opendir(pclient->pwd);
    ERROR_CHECK(dir,NULL,"opendir");

    int ret_ch = chdir(pclient->pwd);
    ERROR_CHECK(ret_ch,-1,"chdir");

    /*先遍历一遍查看有多少个文件，再创建多少个结点*/
    int count = 0;
    struct dirent *dirent_p;
    while((dirent_p = readdir(dir))!= NULL){
        ++count;
    }
    struct dirent **dir_arr = (struct dirent**)malloc(sizeof(struct dirent*)*count);
    ERROR_CHECK(dir_arr,NULL,"dir_arr");
    rewinddir(dir);

    /*存入数组中*/
    int idex = 0;
    while((dirent_p = readdir(dir))!= NULL){
        dir_arr[idex] = dirent_p;
        ++idex;
    }
    /*排序*/
    qsort(dir_arr,count,sizeof(struct dirent*),compare);

    long total_size = 0;
    /*循环发送指针数组中文件信息*/
    train_t train;
    for(int i = 0;i < count; ++i){
        struct stat stat_buf;
        int ret = stat(dir_arr[i]->d_name,&stat_buf);
        total_size += stat_buf.st_blocks;
        ERROR_CHECK(ret,-1,"stat");

        char mode_str[11] = {0};
        trans_rwx(stat_buf.st_mode,mode_str);
        char time_str[100] = {0};
        trans_time(stat_buf.st_mtim.tv_sec,time_str);

        char info[4096] = {0};
        sprintf(info,"%s %2lu %s %s %5lu %13s %s",
                mode_str,
                stat_buf.st_nlink,
                getpwuid(stat_buf.st_uid)->pw_name,
                getgrgid(stat_buf.st_gid)->gr_name,
                stat_buf.st_size,
                time_str,
                dir_arr[i]->d_name);
        bzero(&train,sizeof(train));
        train.length = strlen(info);
        strcpy(train.data,info);
        /* printf("%s ",train.data); */
        send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);
    }
    char blok[256] = {0};
    sprintf(blok,"总用量 %lu",(total_size * 512)/1024);
    bzero(&train,sizeof(train));
    train.length = strlen(blok);
    strcpy(train.data,blok);
    send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);

    //发送退出信号
    bzero(&train,sizeof(train));
    send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);
    free(dir_arr);
    closedir(dir);
    return 0;
}

int doPuts(client_t *pclient){
    recvFile(pclient->fd);
    return 0;
}
int doGets(client_t *pclient,char *file){
    sendFile(pclient->fd,file);
    return 0;
}
int doRemove(client_t *pclient,char *file){
    train_t train;
    if(unlink(file)==0){
        printf("File deleted successfully.\n");
        strcpy(train.data,"Y");
        train.length = strlen(train.data);
        send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);
    }else{
        printf("File deleted error.\n");
        strcpy(train.data,"N");
        train.length = strlen(train.data);
        send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);
    }
    return 0;
}
int doMkdir(client_t *pclient,char *dir){
    train_t train;
    if(mkdir(dir,0755)==0){
        printf("Dir create successfully.\n");
        strcpy(train.data,"Y");
        train.length = strlen(train.data);
        send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);
    }else{
        printf("Dir create error.\n");
        strcpy(train.data,"N");
        train.length = strlen(train.data);
        send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);
    }
    return 0;
}
int doRmdir(client_t *pclient,char *dir){
    train_t train;
    if(rmdir(dir)==0){
        printf("Dir deleted successfully.\n");
        strcpy(train.data,"Y");
        train.length = strlen(train.data);
        send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);
    }else{
        printf("Dir deleted error.\n");
        strcpy(train.data,"N");
        train.length = strlen(train.data);
        send(pclient->fd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
        send(pclient->fd,train.data,train.length,MSG_NOSIGNAL);
    }
    return 0;
}


/* 转换权限 */
static void trans_rwx(mode_t mode,char *mode_str)
{
    /* 3*3+1+'\0' */
    //第一个位置是文件格式，先留着
    mode_str[1] = (mode & 0400)? 'r':'-';
    mode_str[2] = (mode & 0200)? 'w':'-';
    mode_str[3] = (mode & 0100)? 'x':'-';
    mode_str[4] = (mode & 0040)? 'r':'-';
    mode_str[5] = (mode & 0020)? 'w':'-';
    mode_str[6] = (mode & 0010)? 'x':'-';
    mode_str[7] = (mode & 0004)? 'r':'-';
    mode_str[8] = (mode & 0002)? 'w':'-';
    mode_str[9] = (mode & 0001)? 'x':'-';

    mode_str[10] = '\0';

    /* 查看inode */
    switch(mode & S_IFMT){
    case S_IFBLK: mode_str[0] = 'b';  break;
    case S_IFCHR: mode_str[0] = 'c';  break;
    case S_IFSOCK: mode_str[0] = 's';  break;
    case S_IFLNK: mode_str[0] = 'l';  break;
    case S_IFDIR: mode_str[0] = 'd';  break;
    case S_IFIFO: mode_str[0] = 'p';  break;
    case S_IFREG: mode_str[0] = '-';  break;
    default:mode_str[0] = '?';break;
    }
}

/* 转换时间 */
static void trans_time(time_t mtime,char *time_str)
{
    struct tm* st_tm = localtime(&mtime);
    sprintf(time_str,"%2d月 %2d %02d:%02d",
            st_tm->tm_mon+1,
            st_tm->tm_mday,
            st_tm->tm_hour,
            st_tm->tm_min);
}

static int compare(const void *a,const void *b)
{
    /*按照字典顺序排序*/
    struct dirent * dir_a = *(struct dirent **)a;
    ERROR_CHECK(dir_a,NULL,"dir_a");
    struct dirent * dir_b = *(struct dirent **)b;
    ERROR_CHECK(dir_b,NULL,"dir_b");
    /* puts("1\n"); */
    return strcasecmp(dir_a->d_name,dir_b->d_name);
}


//结构体函数
PathNode *pathnode_create(char *realpath) {
    PathNode *new_node = (PathNode *)calloc(1,sizeof(PathNode));
    if (new_node == NULL){
        printf("failure in pathnode_create\n");
        return NULL;
    }
    strncpy(new_node->filePath,realpath,sizeof(new_node->filePath)-1);
    new_node->next = NULL;
    new_node->prev = NULL;
    return new_node;
}

//初始化栈
PathStack *pathstack_init(){
    PathStack *stack = (PathStack *)calloc(1,sizeof(PathStack));
    ERROR_CHECK(stack,NULL,"pathstackInit");
    stack->top = NULL;
    stack->bottom = NULL;
    stack->size = 0;
    return stack;
}
//入栈
void pathstack_push(char *realpath,PathStack *stack){
    PathNode *new_node = pathnode_create(realpath);
    while(new_node == NULL){
        return;
    }
    if(stack->size == 0){
        stack->top = new_node;
        stack->bottom = new_node;
    }else{
        new_node->prev = stack->top;
        stack->top->next = new_node;
        stack->top = new_node;
    }
    ++stack->size;
}

//弹栈
void pathstack_pop(PathStack *stack) {
    if (stack->size == 0) {
        printf("this is the top of directory no need to delete\n");
        return;
    }
    PathNode *curr = stack->top;
    if(stack->size == 1){
        stack->top = NULL;
        stack->bottom = NULL;
    }else{
        stack->top = curr->prev;
        stack->top->next = NULL;
    }
    free(curr);
    --stack->size;
}

//栈销毁和节点销毁函数
void pathstack_free(PathStack *stack) {
    PathNode *curr = stack->bottom;
    while (curr) {
        PathNode *next = curr->next;
        free(curr);
        curr = next;
    }
    free(stack);
}
//打印栈
void print_stack(PathStack *stack) {
    printf("当前路径栈：");
    PathNode *curr = stack->bottom;
    while (curr) {
        printf("/%s", curr->filePath);
        curr = curr->next;
    }
    printf("\n");
}


////cd专用fake_recvn
//static int fake_recvn(int sockfd, void *buf, int length) {
//    static int call_count = 0;
//    if (call_count == 0) {
//        int *plen = (int *)buf;
//        *plen = strlen(g_test_path);
//    } else if (call_count == 1) {
//        memcpy(buf, g_test_path, strlen(g_test_path));
//    }
//    call_count++;
//    if (call_count == 2) {  // 重置，保证每次调用 test_doCd 都从 0 开始
//        call_count = 0;
//    }
//    return length;
//}


